package com.woniuxy.service.impl;

import com.alibaba.fastjson.JSON;
import com.woniuxy.entity.KillBook;
import com.woniuxy.entity.KillOrder;
import com.woniuxy.producer.TopicProducer;
import com.woniuxy.service.SecKillService;
import com.woniuxy.util.SnowflakeIdGenerator;
import com.woniuxy.util.UserConenxt;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.concurrent.TimeUnit;

/**
 * @author dingpf
 * @version 1.0
 * @description
 * @create 2025/4/28 14:20
 */
@Service
public class SecKillServiceImpl implements SecKillService {

    @Resource
    private RedisTemplate redisTemplateInit;

    @Resource
    private TopicProducer topicProducer;

    /**
     * 接受秒杀书籍信息，放入redis。还要保存到秒杀表中
     * 使用rabbitmq改造；
     * 书籍信息只会在开始时间前10分钟进入redis！
     *
     * TTL时间= 开始时间 - 当前时间 - 10分钟
     *
     * @param killBook
     */

   // SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

    @Override
    public void addKillBook(KillBook killBook) {
      //  Date startDate  = sdf.parse(killBook.getStartTime());
        //把时间转成时间戳
      // long subTime = startDate.getTime() - System.currentTimeMillis();
     //  if (subTime > 0){
      //     long TTL = subTime - 10 * 60 * 1000;
           //调用生产者发消息
          // redisTemplateInit.opsForHash().put("SECKILLSERVICEIMPL:ADDKILLBOOK",killBook.getBookId()+"",killBook);
      // }


    }

    /**
     * 查询所有秒杀书籍
     * @return
     */
    @Override
    public List<KillBook> queryAll() {
        Map<String,KillBook> killBookMap = redisTemplateInit.opsForHash().entries("SECKILLSERVICEIMPL:ADDKILLBOOK");
        Iterator<Map.Entry<String, KillBook>> iterator = killBookMap.entrySet().iterator();
        List<KillBook> killBooks = new ArrayList<>();
        //循环map,得到所有value值，放入集合中
        while (iterator.hasNext()){
            Map.Entry<String, KillBook> next = iterator.next();
            killBooks.add( next.getValue());
        }

        return killBooks;
    }

    @Override
    public KillBook queryDetail(Integer bookId) {
        KillBook cacheKillBook =
                (KillBook)redisTemplateInit.opsForHash().get("SECKILLSERVICEIMPL:ADDKILLBOOK", bookId + "");
        return cacheKillBook;
    }

    /**
     * 用户抢购
     * 1：判断书籍库存是否足够
     * 2：减库存
     * 3：生成订单
     * 4：写入订单（该成异步写）
     *
     * 分布式锁
     * 应用场景：1：对共享变量出现了非原子性操作 2：项目集群部署，或者分布式部署（分开部署的方式）
     * 怎么实现分布式锁
     * 1：利用数据库 2：利用redis 3：利用zookeeper
     *
     * redis实现分布式锁
     * 原理：就是利用redis的setnx指令实现的。
     *      setnx指令：setnx(key，val),放入redis时，会判断该key是否存在，如果不存在就可以放入
     *                如果存在就不能放入
     *
     * @param id
     * @return
     */
    @Override
    public Boolean startKill(Integer id) {

        //setIfAbsent() 就是封装的setnx指令
        String uuid = null;
        try {
            //加锁时把线程标识放入value中
            uuid = UUID.randomUUID().toString();
            Boolean aBoolean = redisTemplateInit.opsForValue().setIfAbsent("lock", uuid,30, TimeUnit.SECONDS);
            KillBook cacheKillBook = null;
            if (aBoolean){
                 cacheKillBook =
                        (KillBook)redisTemplateInit.opsForHash().get("SECKILLSERVICEIMPL:ADDKILLBOOK", id + "");

                if (cacheKillBook == null ||  cacheKillBook.getKillNum() <= 0){
                    return false; //抢购结束
                }
                cacheKillBook.setKillNum(cacheKillBook.getKillNum() - 1);
               // System.out.println("剩余库存："+cacheKillBook.getKillNum());
                redisTemplateInit.opsForHash().put("SECKILLSERVICEIMPL:ADDKILLBOOK",id + "",cacheKillBook);

            } else {
                //没有获取到锁的线程
                return false;
            }
            //异步生成订单
            KillOrder killOrder = new KillOrder();

            killOrder.setKillNum(1);
            killOrder.setStatus(1+"");
            killOrder.setPrice(cacheKillBook.getOldPrice());
            killOrder.setBookId(cacheKillBook.getBookId());
            Integer userId = UserConenxt.getUserId();
            killOrder.setUserId(userId);

            SnowflakeIdGenerator sfg = new SnowflakeIdGenerator();
            String orderNum = String.valueOf( sfg.nextId());
            killOrder.setKillOrderNum(orderNum);
            //都要给过期时间,一定大于网络波动时间
            redisTemplateInit.opsForValue().set(orderNum,orderNum,10,TimeUnit.MINUTES);
            topicProducer.send("killOrder",JSON.toJSONString(killOrder));

            return true;

        } catch (Exception e){
            throw new RuntimeException();
        } finally {
            //只能释放当前线程自己加的锁
            if (uuid.equals(redisTemplateInit.opsForValue().get("lock"))){
                redisTemplateInit.delete("lock");
            }
        }

    }
}
